﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using xplang.run;
using xplang.abstractions;
using xplang.expression;
using xplang.errors;
using xplang.contexts;
using xplang.statements;

namespace xplang.parse
{
  public class CompilerForStatements : CompilerForImplementatedCode
  {
    public CompilerForStatements(ClassMethod method, ClassDecl declaringClass, Token destination, Compiler parentCompiler, ImplementationCode code, CompilerForExpressionSupport support)
      : base(declaringClass, parentCompiler, code)
    {
      this.method = method;
      this.destination = destination;
      this.support = support;
    }

    public readonly ClassMethod method;
    public readonly Token destination;
    public readonly CompilerForExpressionSupport support;

    public override OpCode CompileImplementatedCode(ImplementationCode code)
    {
      Token start = current;
      if (!checkOperator("{"))
      {
        new StatementBlockExpectedError(start);
        return null;
      }
      Expression stmt = null;
      if (!compileStatements(ref stmt, false, false))
      {
        new StatementBlockExpectedError(start);
        return null;
      }
      checkEof(true);
      return stmt;
    }

    public bool compileStatements(ref Expression statement, bool required, bool embbed)
    {
      if (isOperator("{"))
      {
        Token start = current;
        nextToken();
        StatementBlock stmts = new StatementBlock();
        while (current != null && !isOperator("}"))
        {
          CompilerForExpression comp = new CompilerForExpression(declaringClass, method, current, null, this, null, support);
          Expression stmt = null;
          Token p = current;
          if (!(comp.compileExpression(ref stmt)) || p == current)
          {
            new StatementExpectedError(current);
            return false;
          }
          if (!(stmt is Statement) || (!(stmt as Statement).isBlock()))
            if (!checkOperator(";"))
              new OperatorExpectedError(current);
            else
              nextToken();
          if (stmt != null)
            stmts.statements.Add(stmt);
        }
        if (required && stmts.statements.Count == 0)
        {
          new StatementExpectedError(code.tokens.First());
          return false;
        }
        if (embbed && isEof())
        {
          new StatementBlockExpectedError(start);
          return false;
        }
        checkOperator("}");
        nextToken();
        statement = stmts;
      }
      else
      {
        if (!embbed)
        {
          checkOperator("{");
          return false;
        }
        CompilerForExpression comp = new CompilerForExpression(declaringClass, method, current, null, this, null, support);
        Expression stmt = null;
        if (!(comp.compileExpression(ref stmt)) || stmt == null)
        {
          new StatementExpectedError(current);
          return false;
        }
        if (!(stmt is Statement) || (!(stmt as Statement).isBlock()))
          if (!checkOperator(";"))
            new OperatorExpectedError(current);
          else
            nextToken();
        statement = stmt;
      }
      return true;
    }
  }
}
